#include "m_pdo.h"
#include "segment.h"
#include "span.h"
#include "common.h"
#include "helper.h"
#include "agent.h"
// #include "skywalking_client.h"

#include <map>
#include <string>
#include <vector>
#include <malloc.h>

#include "ext/pdo/php_pdo_driver.h"

void monitorpro_pdo_handler(zend_execute_data *execute_data, long start_micro_time, long end_micro_time, std::string class_name, std::string function_name)
{
    // 初始化参数
    std::string host = "127.0.0.1";
    std::string port = "3306";
    std::string addr = "";
    std::string sql = "";
    std::string err = "";
    std::string query = "";
    std::string statement = "";

    // 获取数据库连接地址
    zval *obj = execute_data->object;
    pdo_dbh_t *dbh = (pdo_dbh_t *)zend_object_store_get_object(obj TSRMLS_CC);
    std::string dsn = dbh->data_source;
    std::vector<std::string> dsn_attrs = split(dsn, ";");
    for (auto attr : dsn_attrs)
    {
        std::vector<std::string> kv = split(attr, "=");
        if (kv[0] == "host")
        {
            host = kv[1];
        }
        if (kv[0] == "port")
        {
            port = kv[1];
        }
    }
    dsn_attrs.clear();
    std::vector<std::string>().swap(dsn_attrs);
    malloc_trim(0);

    addr = host + ":" + port;

    // 获取参数值
    zval *arg = func_get_arg(execute_data, 1);
    if (arg != nullptr && Z_TYPE_P(arg) == IS_STRING)
    {
        statement = Z_STRVAL_P(arg);
        std::vector<std::string> sql_str = split(statement, " ");
        sql = sql_str[0];
        sql_str.clear();
        std::vector<std::string>().swap(sql_str);
        malloc_trim(0);
    }

    // 获取错误信息
    pdo_stmt_t *stmt = dbh->query_stmt;
    pdo_error_type *pdo_err = &dbh->error_code;
    zval error_value;
    array_init(&error_value);
    add_next_index_string(&error_value, *pdo_err, 1);
    if (dbh->methods->fetch_err)
    {
        dbh->methods->fetch_err(dbh, stmt, &error_value);
        zval **value;
        if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(&error_value), 2, (void **)&value))
        {
            err = Z_STRVAL_PP(value);
        }
    }

    query = class_name + "->" + function_name + "::" + sql;

    // SkywalkingClient *skywalking_client = SkywalkingClient::newInstance();
    // Segment *segment = skywalking_client->getSegment();
    // auto *span = segment->createSpan(SkySpanType::Exit, SkySpanLayer::Database, 8003);
    // span->setOperationName(class_name + "->" + function_name);
    // span->addTag("db.statement", statement);
    // span->setPeer(addr);
    // span->setStartTime(start_micro_time / 1000);
    // span->setEndTime(end_micro_time / 1000);

    push_db_data(addr, query, err, end_micro_time - start_micro_time);
}

void monitorpro_pdo_stmt_handler(zend_execute_data *execute_data, long start_micro_time, long end_micro_time, std::string class_name, std::string function_name)
{
    // 初始化参数
    std::string host = "127.0.0.1";
    std::string port = "3306";
    std::string addr = "";
    std::string sql = "";
    std::string err = "";
    std::string query = "";

    // 获取数据库连接地址
    zval *obj = execute_data->object;
    pdo_stmt_t *stmt = (pdo_stmt_t *)zend_object_store_get_object(obj TSRMLS_CC);
    pdo_dbh_t *dbh = stmt->dbh;
    std::string dsn = dbh->data_source;
    std::vector<std::string> dsn_attrs = split(dsn, ";");
    for (auto attr : dsn_attrs)
    {
        std::vector<std::string> kv = split(attr, "=");
        if (kv[0] == "host")
        {
            host = kv[1];
        }
        if (kv[0] == "port")
        {
            port = kv[1];
        }
    }
    dsn_attrs.clear();
    std::vector<std::string>().swap(dsn_attrs);
    malloc_trim(0);

    addr = host + ":" + port;

    // 获取函数传参
    std::string sql_string = stmt->query_string;
    std::vector<std::string> sql_str = split(sql_string, " ");
    sql = sql_str[0];
    sql_str.clear();
    std::vector<std::string>().swap(sql_str);
    malloc_trim(0);

    // 获取错误信息
    pdo_error_type *pdo_err = &dbh->error_code;
    zval error_value;
    array_init(&error_value);
    add_next_index_string(&error_value, *pdo_err, 1);
    if (dbh->methods->fetch_err)
    {
        dbh->methods->fetch_err(dbh, stmt, &error_value);
        zval **value;
        if (SUCCESS == zend_hash_index_find(Z_ARRVAL_P(&error_value), 2, (void **)&value))
        {
            err = Z_STRVAL_PP(value);
        }
    }

    query = class_name + "->" + function_name + "::" + sql;

    // SkywalkingClient *skywalking_client = SkywalkingClient::newInstance();
    // Segment *segment = skywalking_client->getSegment();
    // auto *span = segment->createSpan(SkySpanType::Exit, SkySpanLayer::Database, 8003);
    // span->setOperationName(class_name + "->" + function_name);
    // span->addTag("db.statement", sql_string);
    // span->setPeer(addr);
    // span->setStartTime(start_micro_time / 1000);
    // span->setEndTime(end_micro_time / 1000);

    push_db_data(addr, query, err, end_micro_time - start_micro_time);
}
